import { readFileSync } from 'fs-extra';
import { join } from 'path';
import Vue from 'vue/dist/vue';
import { ActionHead } from './actionHead';
import { ActionProp } from './actionProp';

type Selector<$> = { $: Record<keyof $, any | null> }
type PanelThis = Selector<typeof $> & { dump: any, vm: Vue };

export enum PropType {
    to,
    from,
    free,
}
export enum ValueType {
    relative,
    absolute,
}
enum AcitonType {
    opacity = 1,
    scale = 1 << 1,
    position = 1 << 2,
    angle = 1 << 3,
}
enum EventType {
    view_show = 1,
    view_hide = 2,
}
const ActionTypeKeyOnly = Object.keys(AcitonType).filter((v) => isNaN(parseInt(v)));
export const template = readFileSync(join(__dirname, '../../../static/template/inspector-action.html'), 'utf-8')

export const style = readFileSync(join(__dirname, '../../../static/style/inspector-action.css'), 'utf-8')

export const $ = {
    app: '#app',
    actionsDump: "#actionsDump",
    actionPropsDump: "#actionPropsDump",
}
export const methods = {

}
exports.ready = function () {
    let panel = this;

    if (this.$.app) {
        const vm = new Vue({
            components: {
                "action-head": ActionHead,
                "action-prop": ActionProp,
            },
            el: this.$.app,
            template: readFileSync(join(__dirname, '../../../static/template/vue/app.html'), 'utf-8'),
            data() {
                return {
                    actionProps: [],

                    eventType: 1,
                    actionFlag: 0,
                    actionType: AcitonType,
                    actionTypeKeyOnly: ActionTypeKeyOnly,
                    unopenAcitonTypes: ActionTypeKeyOnly,

                    scaleProp: null,
                    angleProp: null,
                    opacityProp: null,
                    positionProp: null,

                    lastCompLength: 0,
                };
            },
            mounted() {
            },
            computed: {

            },
            methods: {
                /**
                 * 开关状态改变时的回调
                 * @param index 第几个开关
                 * @param open 是否开启
                 */
                onOpenChange: function (index: number, open: boolean) {
                    if (open) {
                        panel.dump.value.actionFlag.value |= (1 << index);
                    } else {
                        panel.dump.value.actionFlag.value &= ~(1 << index);
                    }
                    panel.$.actionsDump.dispatch('change-dump');

                    if (open && ((1 << index) === AcitonType.opacity)) {
                        this.onOpenOpacity();
                    }
                },
                /**
                 * 开启透明度行动时的回调。
                 * 主要用来自动附加cc.UIOpacity组件
                 */
                onOpenOpacity: async function () {
                    let nodeUUID = this.getNodeUUID();
                    let nodeDump = await this.getNodeDump(nodeUUID);

                    if (this.checkNodeWithoutUIOpacityComp(nodeDump)) {
                        Editor.Message.request("scene", "create-component", {
                            uuid: nodeUUID,
                            component: "cc.UIOpacity"
                        });
                    }
                },
                onPropTypeChange: function (index: number, propType: PropType) {
                    (this.actionProps[index] as any).type.value = propType;
                    (this.$refs as any).propDums[index].dispatch('change-dump');
                },
                onValueTypeChange: function (index: number, value: ValueType) {
                    (this.actionProps[index] as any).valueType.value = value;
                    (this.$refs as any).propDums[index].dispatch('change-dump');
                },
                onEventTypeChange: function (event: any) {
                    let eventType = event.target.value;
                    this.eventType = eventType;

                    let eventStr = EventType[eventType];
                    if (!eventStr) {
                        return;
                    }

                    let eventDump = (this.$refs.eventDump as any)
                    eventDump.dump.value = eventStr;
                    eventDump.dispatch('change-dump');
                },
                onDumpUpdate: async function () {
                    let nodeUUID = this.getNodeUUID();
                    let nodeDump = await this.getNodeDump(nodeUUID);
                    let curCompLength = nodeDump.__comps__.length;

                    if (this.lastCompLength !== curCompLength) {
                        let hasOpacityAction = nodeDump.__comps__.some((comp: any) => comp.type === "Action" && (comp.value.actionFlag.value & 1));
                        if (hasOpacityAction) {
                            if (this.checkNodeWithoutUIOpacityComp(nodeDump)) {
                                console.error("action: opacity子动作需要cc.UIOpacity组件!");
                            }
                        }

                        this.lastCompLength = curCompLength;
                    }
                },
                getNodeUUID: function () {
                    return panel.dump.value.node.value.uuid;
                },
                checkNodeWithoutUIOpacityComp: function (nodeDump: any) {
                    return !nodeDump.__comps__.some((comp: any) => comp.type === "cc.UIOpacity");
                },
                getNodeDump: async function (nodeUUID: string) {
                    return await Editor.Message.request("scene", "query-node", nodeUUID);
                },
                onPreviewClick: async function () {
                    this.executeComponentMethod("playAction");
                },
                onRecordClick: async function () {
                    this.executeComponentMethod("recordProps");
                },
                onRecoverClick: async function () {
                    this.executeComponentMethod("recoverProps");
                },
                executeComponentMethod: async function (funcName: string) {
                    let uuid = panel.dump.value.uuid.value;

                    Editor.Message.request("scene", "execute-component-method", {
                        uuid: uuid,
                        name: funcName,
                    });
                },
            },
        });
        this.vm = vm;
    }
};

export function update(this: PanelThis, dump: any) {
    // console.log("action inspector", "update", dump);

    // 缓存 dump 数据，请挂在 this 上，否则多开的时候可能出现问题
    this.dump = dump;

    let actionBean = dump.value;
    this.$.actionsDump.dump = actionBean.actionFlag;
    (this.vm as any).actionFlag = actionBean.actionFlag.value;

    (this.vm as any).actionProps = [];
    for (let i = 0; i < ActionTypeKeyOnly.length; i++) {
        const propKey = ActionTypeKeyOnly[i];

        let fullKey = `${propKey}Prop`;

        let propValue = actionBean[fullKey].value;
        (this.vm as any)[fullKey] = propValue;
        (this.vm as any).actionProps.push(propValue);
        (this.vm as any).$refs.propDums[i].dump = actionBean[fullKey];
    }

    (this.vm as any).eventType = EventType[actionBean.event.value] || 3;
    (this.vm as any).$refs.easingDump.render(actionBean.easing);
    (this.vm as any).$refs.durationDump.render(actionBean.duration);
    (this.vm as any).$refs.delayDump.render(actionBean.delay);
    (this.vm as any).$refs.resetDump.render(actionBean.reset);
    (this.vm as any).$refs.eventDump.render(actionBean.event);
    (this.vm as any).$refs.nextActionNodesDump.render(actionBean.nextActionNodes);

    (this.vm as any).onDumpUpdate();
}

export function beforeClose() { }

export function close() { }
